﻿using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;

namespace MICZ.CodeBuilder.Commons.JwtExtensions
{
    /// <summary>
    /// JWT配置信息
    /// </summary>
    public class JwtHelper
    {

        public static string USERID = "";
        public static string ID = "";

        /// <summary>
        /// 创建JWT对象
        /// </summary>
        /// <returns></returns>
        public static JwtMsg CreateJWT()
        {
            #region 生成JWT

            //设置过期时间
            var nowTime = DateTime.Now; //现在时间
            var exp = nowTime.AddMinutes(Int32.Parse(ConfigExtensions.ConfigExtensions.GetConfigurationValue("Jwt", "Expiration")));

            //这里可以随意加入自定义的参数，key可以自己随便起
            var claims = new[]
            {
                    //生效时间
                    new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") ,
                    //设置过期时间
                    new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(exp).ToUnixTimeSeconds()}"),
                    //new Claim(ClaimTypes.Name,AuthContextUser.CurrentUser.UserName),
                    //new Claim("UserId",AuthContextUser.CurrentUser.UserId),
                    //new Claim("ID",AuthContextUser.CurrentUser.ID.ToString())
            };

            #region 获取密匙
            var secret = ConfigExtensions.ConfigExtensions.GetConfigurationValue("Jwt", "Secret");
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            #endregion

            var token = new JwtSecurityToken(
                //颁发者
                issuer: ConfigExtensions.ConfigExtensions.GetConfigurationValue("Jwt", "Issuer"),
                //接收者
                audience: ConfigExtensions.ConfigExtensions.GetConfigurationValue("Jwt", "Issuer"),
                //过期时间
                expires: exp,
                //签名证书
                signingCredentials: creds,
                //自定义参数
                claims: claims
                );
            var tokenstr = new JwtSecurityTokenHandler().WriteToken(token);

            #endregion

            return new JwtMsg
            {
                ExpireTime = nowTime.ToString("yyyy-MM-dd HH:mm:ss"),
                JwtStr = tokenstr
            };
        }

        /// <summary>
        /// 创建JWT对象（登录时 调用）
        /// </summary>
        /// <param name="USERID"></param>
        /// <param name="ID"></param>
        /// <returns></returns>
        public static JwtMsg CreateJWT(string USERID, string ID)
        {
            #region 生成JWT

            //设置过期时间
            var nowTime = DateTime.Now; //现在时间
            var exp = nowTime.AddMinutes(Int32.Parse(ConfigExtensions.ConfigExtensions.GetConfigurationValue("Jwt", "Expiration")));

            //这里可以随意加入自定义的参数，key可以自己随便起
            var claims = new[]
            {
                    //生效时间
                    new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") ,
                    //设置过期时间
                    new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(exp).ToUnixTimeSeconds()}"),
                    //new Claim(ClaimTypes.Name,currentUser.UserName),
                    new Claim("USERID",USERID),
                    new Claim("ID",ID.ToString())
            };

            #region 获取密匙
            var secret = ConfigExtensions.ConfigExtensions.GetConfigurationValue("Jwt", "Secret");
            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
            #endregion

            var token = new JwtSecurityToken(
                //颁发者
                issuer: ConfigExtensions.ConfigExtensions.GetConfigurationValue("Jwt", "Issuer"),
                //接收者
                audience: ConfigExtensions.ConfigExtensions.GetConfigurationValue("Jwt", "Issuer"),
                //过期时间
                expires: exp,
                //签名证书
                signingCredentials: creds,
                //自定义参数
                claims: claims
                );
            var tokenstr = new JwtSecurityTokenHandler().WriteToken(token);

            #endregion

            return new JwtMsg
            {
                ExpireTime = exp.ToString("yyyy-MM-dd HH:mm:ss"),
                JwtStr = tokenstr
            };
        }

        /// <summary>
        /// 解析--未启用
        /// </summary>
        /// <param name="jwtStr"></param>
        /// <returns></returns>
        public static dynamic SerializeJWT(string jwtStr)
        {
            var jwtHandler = new JwtSecurityTokenHandler();
            JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr);
            object role = new object(); ;
            object project = new object();
            try
            {
                jwtToken.Payload.TryGetValue("Role", out role);
                jwtToken.Payload.TryGetValue("Project", out project);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }
            var tm = new
            {
                ID = (int)long.Parse(jwtToken.Id),
                //Role = role.ToString(),
                //Project = project.ToString()
            };
            return tm;
        }

        /// <summary>
        /// 解析Token
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public static bool GetPrincipal(string token)
        { // 此方法用解码字符串token，并返回秘钥的信息对象
            try
            {
                var success = true;
                token = token.Replace("Bearer", "").Trim();
                var jwtArr = token.Split('.');
                #region 获取密匙
                var secret = ConfigExtensions.ConfigExtensions.GetConfigurationValue("Jwt", "Secret");
                var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
                //var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
                //var creds = new StringEscapeHandling(key, SecurityAlgorithms.HmacSha256);
                #endregion
                //var a = token.Split('.')[2].GetMd5();
                var header = JsonConvert.DeserializeObject<Dictionary<string, object>>(Base64UrlEncoder.Decode(token.Split('.')[0]));
                var payLoad = JsonConvert.DeserializeObject<Dictionary<string, object>>(Base64UrlEncoder.Decode(token.Split('.')[1]));
                var hs256 = new HMACSHA256(Encoding.UTF8.GetBytes(ConfigExtensions.ConfigExtensions.GetConfigurationValue("Jwt", "Secret")));
                //首先验证签名是否正确（必须的）
                //success = success && jwtArr[2]==Base64UrlEncoder.Encode(hs256.ComputeHash(Encoding.UTF8.GetBytes(string.Concat(jwtArr[0], ".", jwtArr[1]))));
                success = success && string.Equals(jwtArr[2],Base64UrlEncoder.Encode(hs256.ComputeHash(Encoding.UTF8.GetBytes(string.Concat(jwtArr[0], ".", jwtArr[1])))));
                if (!success)
                {
                    return success;//签名不正确直接返回
                }
                //其次验证是否在有效期内（也应该必须）
                var now = ToUnixEpochDate(DateTime.UtcNow);
                success = success && (now >= long.Parse(payLoad["nbf"].ToString()) && now < long.Parse(payLoad["exp"].ToString()));

                //再其次 进行自定义的验证
                //success = success && validatePayLoad(payLoad);
                USERID = payLoad["USERID"].ToString();
                ID = payLoad["ID"].ToString();
                return success;
                #region 第二种解析方法
                //var tokenHandler = new JwtSecurityTokenHandler(); // 创建一个JwtSecurityTokenHandler类，用来后续操作
                //var jwtToken = tokenHandler.ReadToken(token) as JwtSecurityToken; // 将字符串token解码成token对象
                //if (jwtToken == null)
                //    return null;
                //var Secret = ConfigExtensions.ConfigExtensions.GetConfigurationValue("Jwt", "Secret");
                //var symmetricKey = Convert.FromBase64String(Secret); // 生成编码对应的字节数组
                //var validationParameters = new TokenValidationParameters() // 生成验证token的参数
                //{
                //    RequireExpirationTime = true, // token是否包含有效期
                //    ValidateIssuer = false, // 验证秘钥发行人，如果要验证在这里指定发行人字符串即可
                //    ValidateAudience = false, // 验证秘钥的接受人，如果要验证在这里提供接收人字符串即可
                //    IssuerSigningKey = new SymmetricSecurityKey(symmetricKey) // 生成token时的安全秘钥
                //};
                //SecurityToken securityToken; // 接受解码后的token对象
                //var principal = tokenHandler.ValidateToken(token, validationParameters, out securityToken);
                //return principal; // 返回秘钥的主体对象，包含秘钥的所有相关信息
                #endregion
            }
            catch (Exception ex)
            {
                return false;
            }
        }
        public static long ToUnixEpochDate(DateTime date) => (long)Math.Round((date.ToUniversalTime() - new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero)).TotalSeconds);
    }
}
